#!/usr/bin/perl
# add_server_completed.pm
# Copyright (C) 2006, 2007  Stephane Alnet
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 3
# of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
# 

package CCNCore::spool::add_server_completed;
use strict; use warnings;

use CCN::Text;
use CCNCore::IPC::Ticket;

our $D;

sub run
{
    my $step = shift;
    my $id = shift;
    
    my $t = new CCNCore::IPC::Ticket($id);
    
    # Steps:
    #  0 add_server (trigerred from the Web UI in Entry.pm)
    #  1 send new configuration to the manager (so that it knows about the new server)
    #  2 then spool "distribute-keys $server_pk" on the manager
    #  3 send configuration to the new server (via CDN)
    #  4 trigger reconfigure via the web interface

    step_0_completed($t) if $step == 0;
    step_1_completed($t) if $step == 1;
    step_2_completed($t) if $step == 2;
    step_3_completed($t) if $step == 3;
    step_4_completed($t) if $step == 4;
}

sub step_0_completed
{
    my $t = shift;

    # Post-processing Step 0 is the most complex:
    # Use the value returned by the remote server to create the entry in the UI SQL database.
    my $return_value = $t->retrieve_context('return');
    if(not defined $return_value or $return_value eq '')
    {
        # An error occurred (probably wrong password)
        warn 'add_server_completed: invalid empty return value';
        return;
    }

    $return_value = CCN::Text::hex_to_text($return_value);

    my $system_pk = $t->retrieve_context('system_pk');
    my $owner_pk  = $t->retrieve_context('owner_pk');
    my $manager_pk = $t->retrieve_context('manager_pk');
    
    # $return_value now contains the information provided by remote_rpc.
    # Feed it to the _rpc locally.
    use CCNCore::Provisioning::Local;
    my $p = new CCNCore::Provisioning::Local;
    use CCNCore::Database::GUI;
    my $db = new CCNCore::Database::GUI($p);
    
    $db->sql_begin;

    my $server_pk = $db->sql_get(<<'SQL');
        SELECT CASE COUNT(*) WHEN 0 THEN 1 ELSE MAX(pk)+1 END AS pk FROM "server"
SQL

    my $cdn_server = $db->sql_get(<<'SQL',$system_pk);
        SELECT MIN(cdn_downstream_server) FROM server WHERE cdn_downstream_server IS NOT NULL AND system = ?
SQL

    $cdn_server = $server_pk if not defined $cdn_server;

    use IO::Scalar;
    use CCNCore::bootstrap_utils;
    my $fh = new IO::Scalar(\$return_value);
    my @sql = CCNCore::bootstrap_utils::remote_rpc($fh,$system_pk,$server_pk,'NULL',$owner_pk,$cdn_server);

    my $ok = 1;
    for my $sql (@sql)
    {
        $D->log("SQL: $sql");

        $ok = 0
            if not $db->sql_do($sql);
    }
    
    if(not $ok)
    {
        $db->sql_rollback();
        $D->log('failure');
        return;
    }

    # Everything was fine; conclude post-processing of Step 0.
    $db->sql_commit();

    # Proceed with Step 1

    my $t2 = new CCNCore::IPC::Ticket;
    $t2->add_action(1,'add-server-completed 1');
    $t2->add_context('system_pk',$system_pk);
    $t2->add_context('manager_pk',$manager_pk);
    $t2->add_context('server_pk',$server_pk);

    use CCNCore::IPC::Spool;
    my $spool = new CCNCore::IPC::Spool;
    $spool->spool_request("create-sqlite $manager_pk ".$p->server_pk()." ".$t2->ticket());

    $t->completed();
    $t->clear_ticket();
    $D->log('success');
}

sub step_1_completed
{
    my $t = shift;

    my $system_pk = $t->retrieve_context('system_pk');
    my $manager_pk = $t->retrieve_context('manager_pk');
    my $server_pk = $t->retrieve_context('server_pk');

    my $t2 = new CCNCore::IPC::Ticket;
    $t2->add_action(1,'add-server-completed 2');
    $t2->add_context('system_pk',$system_pk);
    $t2->add_context('manager_pk',$manager_pk);
    $t2->add_context('server_pk',$server_pk);
    
    # Proceed with Step 2
    use CCNCore::Provisioning::Local;
    my $p = new CCNCore::Provisioning::Local;
    use CCNCore::Provision::Distributed;
    my $c = new CCNCore::Provision::Distributed($p);
    $c->spool_this($manager_pk,$t2->ticket,"distribute-keys $server_pk");

    $t->completed;
    $t->clear_ticket;
}

sub step_2_completed
{
    my $t = shift;

    my $system_pk = $t->retrieve_context('system_pk');
    my $manager_pk = $t->retrieve_context('manager_pk');
    my $server_pk = $t->retrieve_context('server_pk');

    my $t2 = new CCNCore::IPC::Ticket;
    $t2->add_action(1,'add-server-completed 3');
    $t2->add_context('system_pk',$system_pk);
    $t2->add_context('manager_pk',$manager_pk);
    $t2->add_context('server_pk',$server_pk);
    
    # Proceed with Step 3
    use CCNCore::Provisioning::Local;
    my $p = new CCNCore::Provisioning::Local;

    use CCNCore::IPC::Spool;
    my $spool = new CCNCore::IPC::Spool;
    $spool->spool_request("create-sqlite $server_pk ".$p->server_pk()." ".$t2->ticket());

    $t->completed;
    $t->clear_ticket;
}

sub step_3_completed
{
    my $t = shift;

    my $system_pk = $t->retrieve_context('system_pk');
    my $manager_pk = $t->retrieve_context('manager_pk');
    my $server_pk = $t->retrieve_context('server_pk');

    my $t2 = new CCNCore::IPC::Ticket;
    $t2->add_action(1,'add-server-completed 4');
    $t2->add_context('system_pk',$system_pk);
    $t2->add_context('manager_pk',$manager_pk);
    $t2->add_context('server_pk',$server_pk);
    
    # Proceed with Step 4
    use CCNCore::Provisioning::Local;
    my $p = new CCNCore::Provisioning::Local;
    use CCNCore::Provision::Distributed;
    my $c = new CCNCore::Provision::Distributed($p);
    # Still can't do this: the server hasn't been configured, so it isn't talking to us!
    # $c->spool_this($server_pk,$t2->ticket,"configure");
    # Actually this wasn't working either because:
    # die Cannot resolve s1.server.carrierclass.net.voice:  at /usr/share/perl5/XML/Stream.pm line 406.
    # (fixed it by adding the proper entries to /etc/hosts).
    # Now we're stuck with the fact that by the time the new server tries to connect to the Jabber server,
    # it hasn't been configured there yet.
    $c->spool_this($manager_pk,$t2->ticket,"configure-remote $server_pk");
    

    $t->completed;
    $t->clear_ticket;
}

sub step_4_completed
{
    my $t = shift;

    my $system_pk = $t->retrieve_context('system_pk');
    my $manager_pk = $t->retrieve_context('manager_pk');
    my $server_pk = $t->retrieve_context('server_pk');

    # Step 4 has been completed, system is now in the database
    # and configured.
    system('echo "Node has been added to the system." | /usr/bin/wall');

    $t->completed;
    $t->clear_ticket;
}


1;